#!/usr/bin/env python

################################################################################
#   Copyright 2010 Jason Hoover
#
#
#   This file is part of AutoCache.
#
#   AutoCache is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Lesser General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   AutoCache is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.

#   You should have received a copy of the GNU Lesser General Public License
#   along with AutoCache.  If not, see <http://www.gnu.org/licenses/>.
################################################################################

import threading

from ac_common import ac_settings, ac_compiletargets, ac_log
from ac_cache import *

################################################################################
# Set the request index positions based on the "concurrency" setting.
# 
# In concurrent mode, requests are in in the format: 
# "ID URL ip/fqdn ident method key-pairs"
#
# ID         - A Unique ID of the request.
# URL        - The incoming URL
# ip         - Request Source IP
# fqdn       - The request fqdn (hostname)
# method     - The HTTP method.
# key-pairs  - Unknown.
#
# In standard non-concurrent mode, there is no ID. The lambda req_id changes
# whether index 0 is prepended to the result, or simply a null string.
################################################################################
if ac_settings["concurrency"] is True:
    req_method = 4
    req_url = 1
    req_id = lambda input: input[0]

else:
    req_method = 3
    req_url = 0
    req_id = lambda input: ""


################################################################################
# ac_processrequest - Threaded request processor.
################################################################################
def ac_takerequest(request):

    try:
        ac_log.debug("Got request " + str(request))

        # If it's not a GET request, we don't give a fuck.
        if request[req_method] not in ("GET", "HEAD"):
            sys.stdout.write(req_id(request) + " \n")
            sys.stdout.flush()
            return

        # Check the request against the regexps.
        if targets.match(request[req_url]):

            # Store the cached target to see if there's anything. 
            # ac_checkup returns either the cached target, or an error.
            ac_log.debug("Found a match for last request.")
            cached_target = ac_checkup(request[req_url])
    
            if isinstance(cached_target,str):
                    
                sys.stdout.write(req_id(request) + " " + cached_target + "\n")
                sys.stdout.flush()
                return

            else:

                sys.stdout.write(req_id(request) + " \n")
                sys.stdout.flush()
                ac_update(request[req_url])
                return

        # If it matches nothing, print this.
        ac_log.debug("Returning non-matching result.")
        sys.stdout.write(req_id(request) + " \n")
        sys.stdout.flush()

    except IndexError:
        ac_log.error("Values missing from: " + str(request))

    except:
        ac_log.exception("SUBMIT BUG REPORT - Fatal error processing: " + 
                         str(request))
    
################################################################################
# main - Here we define the main loop. Note that there are two different 
# versions. One which supports concurrency using threads of the 
# ac_concurrentrequest function, and one which simply includes it's same logic, 
# but with slightly different variables.
################################################################################
def main():

        ac_stateinit()

        try:
            while True:

                request=sys.stdin.readline().rstrip().split()

                if request == []:
                    ac_log.info("Autocache asked to quit by squid. Goodbye.")
                    return

                # Split the request into a tuple.
                # According to squid wiki come in the format of:
                # "URL ip/fqdn ident method key-pairs"
                threading.Thread(target=ac_takerequest,args=(request,)).start()

        except (EOFError,KeyboardInterrupt):
            ac_log.debug("Got EOF or CTRL-C, all done!")
            return

        except:
            ac_log.exception("SUBMIT BUG REPORT - Serious exception in main loop. Quitting.")
            return

try:
    targets=ac_compiletargets()
    ac_log.info("autocache 0.1.0 started sucessfully.")
    main()

except:
    ac_log.exception("SUBMIT BUG REPORT - Unhandled exception starting up.")
